﻿using Cfg.Exceptions;
using Cfg.ValidationAttributes;
using NUnit.Framework;

namespace Cfg.Test.Validators
{
    [TestFixture]
    public class RequiredAttributeTest
    {
        public interface ITestConfig
        {
            [Required("RequiredOnFieldThatDoesNotExist")]
            int X { get; } 

            IRequiredAttributeTestSection Required { get; }
        }

        public interface IRequiredAttributeTestSection
        {
            [Required("RequiredOnStringFieldWithEmptyValue")]
            string StringWithEmptyValue { get; }

            [Required("RequiredOnIntFieldWithEmptyValue")]
            int IntWithEmptyValue { get; }

            [Required]
            string StringWithValue { get; }
        }

        [Test]
        public void RequiredNoContext()
        {
            try
            {
                AppSettings.Init<ITestConfig>();
                Assert.Fail("Validation should fail");
            }
            catch (ConfigValidationException ex)
            {
                Assert.AreEqual(typeof(ITestConfig), ex.ConfigType);

                // since context was not defined on init, all validations should be executed
                Assert.AreEqual(3, ex.ValidationErrors.Length);

                // but still valid properties values should be set
                var cfg = AppSettings.Get<ITestConfig>();
                Assert.AreEqual("value", cfg.Required.StringWithValue);
            }
        }

        [Test]
        public void RequiredOnFieldThatDoesNotExist()
        {
            try
            {
                AppSettings.Init<ITestConfig>("RequiredOnFieldThatDoesNotExist");
                Assert.Fail("Validation should fail");
            }
            catch (ConfigValidationException ex)
            {
                Assert.AreEqual(typeof(ITestConfig), ex.ConfigType);

                // only one fileld is in current context
                Assert.AreEqual(1, ex.ValidationErrors.Length);
                Assert.AreEqual("X", ex.ValidationErrors[0].Key);
                Assert.AreEqual("Field is required, but value was not found", ex.ValidationErrors[0].Error);
            }
        }

        [Test]
        public void RequiredOnStringFieldWithEmptyValue()
        {
            try
            {
                AppSettings.Init<ITestConfig>("RequiredOnStringFieldWithEmptyValue");
                Assert.Fail("Validation should fail");
            }

            catch (ConfigValidationException ex)
            {
                Assert.AreEqual(typeof (ITestConfig), ex.ConfigType);

                // only one fileld is in current context
                Assert.AreEqual(1, ex.ValidationErrors.Length);
                Assert.AreEqual("Required.StringWithEmptyValue", ex.ValidationErrors[0].Key);
                Assert.AreEqual("Field is required, but value was not found", ex.ValidationErrors[0].Error);
            }
        }

        [Test]
        public void RequiredOnIntFieldWithEmptyValue()
        {
            try
            {
                AppSettings.Init<ITestConfig>("RequiredOnIntFieldWithEmptyValue");
                Assert.Fail("Validation should fail");
            }

            catch (ConfigValidationException ex)
            {
                Assert.AreEqual(typeof (ITestConfig), ex.ConfigType);

                // only one fileld is in current context
                Assert.AreEqual(1, ex.ValidationErrors.Length);
                Assert.AreEqual("Required.IntWithEmptyValue", ex.ValidationErrors[0].Key);
                Assert.AreEqual("Field is required, but value was not found", ex.ValidationErrors[0].Error);
            }
        }
    }
}
